package ffte.misc

import spinal.core._
import spinal.lib._

/**
 * Pulse delay utility for FFT timing management
 *
 * This class provides configurable pulse delay functionality for managing
 * timing relationships in FFT implementations. It supports both small
 * delays using direct registers and large delays using FIFO-based
 * timestamping.
 *
 * Key Features:
 * - Configurable delay depth (d) and burst size (N)
 * - Automatic optimization based on delay size
 * - FIFO-based timestamping for large delays
 * - Register-based delays for small delays
 *
 * Applications:
 * - Managing pipeline timing in streamed FFTs
 * - Aligning data bursts across different processing stages
 * - Implementing control signal synchronization
 * - Handling variable-latency operations
 *
 * @param d Delay depth in clock cycles
 * @param N Expected burst size for FIFO sizing optimization
 */
case class delay(d:Int,N:Int) {

    /**
     * Delay a pulse signal by specified cycles
     *
     * Implements pulse delay with automatic optimization based on delay size.
     * Uses direct register delays for small delays (<16 cycles) and FIFO-based
     * timestamping for larger delays.
     *
     * Implementation Strategy:
     * - Small delays (d < 16): Direct register chain using SpinalHDL Delay
     * - Large delays (d ≥ 16): FIFO-based timestamp system for efficiency
     *
     * @param s Input pulse signal to delay
     * @param fire Clock enable/fire signal for timing control
     * @return Delayed pulse signal
     */
    def delayPulse(s:Bool,fire:Bool) = {
        if (d<16) {
            // Small delay: use direct register chain
            Delay(s,d,fire,False)
        } else
        {
            // Large delay: use FIFO-based timestamp system
            val da = new Area {

                /** Bit width for delay counter (with headroom) */
                val dW = log2Up(d)+2

                /** FIFO for storing timestamps of pending pulses */
                val delayFifo = new syncfifo(UInt(dW bits),(1<<dW)/N+8)

                /** Active flag for timing control (currently unused) */
                val active = RegInit(False)

                /** Cycle counter for timestamp generation */
                val cnt    = RegInit(U(0,dW bits))

                // Push timestamp when input pulse occurs
                delayFifo.io.push.valid := fire & s
                delayFifo.io.push.payload := cnt+d
                delayFifo.io.flush := False

                // Increment counter on each fire cycle
                when(fire) {
                    cnt    := cnt+1
                }

                // Check if current cycle matches timestamp of pending pulse
                val hit = fire & (cnt===delayFifo.io.pop.payload) & delayFifo.io.pop.valid
                delayFifo.io.pop.ready := hit
            }
            da.hit
        }
    }
}